//
// Created by ningjian on 18-6-7.
//

#include <netinet/in.h>
#include <iostream>
#include "RTPBufferReader.hpp"
#include "RTPPackage.hpp"
#include <sstream>
#include <sys/stat.h>

using namespace std;

RTPBufferReader::RTPBufferReader(long timespace, std::string out_dir)
{
    this->timespace = timespace;
    this->out_dir = out_dir;
}


RTPBufferReader::~RTPBufferReader() {
    if (stream_to_mp4) {
        stream_to_mp4->Finsh();
        delete stream_to_mp4;
    }
}

bool RTPBufferReader::ReadBuffer(uint8_t *data, size_t len) {

    memcpy(socket_buffer + socket_offset, data, len);
    socket_offset += len;

    while (true) {

        if (stream_to_mp4 == NULL) {
            std::string path_prefix = this->out_dir + "/" + std::to_string(BCD2long(socket_buffer + 8, 6));
            path_prefix += "_CH";
            path_prefix += std::to_string((int) socket_buffer[14]);

            stream_to_mp4 = new StreamToMP4(path_prefix, this->timespace, AV_CODEC_ID_H264, AV_CODEC_ID_NONE);

            stream_to_mp4->Init();
        }


        std::cout << "recv RTP HEAD:" << bytes2HexString(socket_buffer,30) << endl;

        //负载类型
        uint8_t PT = socket_buffer[5] & 0b01111111;


        uint8_t data_type = socket_buffer[15];
        data_type = (data_type >> 4);

        uint8_t subpackage_flag = socket_buffer[15];
        subpackage_flag = (subpackage_flag << 4);
        subpackage_flag = (subpackage_flag >> 4);

        uint16_t data_len;
        size_t data_offset = 30;
        if (data_type == A_F || data_type == T_T) {
            memcpy(&data_len, socket_buffer + 24, 2);
            data_offset = 26;
        } else {
            memcpy(&data_len, socket_buffer + 28, 2);
            data_offset = 30;
        }

        uint16_t sn;
        memcpy(&sn, socket_buffer + 6, 2);
        sn = ntohs(sn);


        data_len = ntohs(data_len);

        if (data_len == 0) break;

        if (socket_offset >= data_len + data_offset) {

//            std::cout << "recv RTP HEAD: " << bytes2HexString(socket_buffer, 30) << endl;
//            std::cout << "data_sn : " << sn << endl;
//            std::cout << "data_len : " << data_len << endl;

            if (PT == PT_H264)// h264 video
            {
                memcpy(v_packet_buffer_data + v_packet_buffer_offset, socket_buffer + data_offset, data_len);
                v_packet_buffer_offset += data_len;

                if (subpackage_flag == SPF_ATOM || subpackage_flag == SPF_LAST) { //一个完整的包接收成功
                    //std::cout << "recv package : " << bytes2HexString(v_packet_buffer_data, 30) << std::endl;
                    stream_to_mp4->WriteVideoFrameData(v_packet_buffer_offset, v_packet_buffer_data);
                    v_packet_buffer_offset = 0;

                }

            } else if (PT == PT_AAC) { // aac audio

                memcpy(a_packet_buffer_data + a_packet_buffer_offset, socket_buffer + data_offset, data_len);
                a_packet_buffer_offset += data_len;
                if (subpackage_flag == SPF_ATOM || subpackage_flag == SPF_LAST) { //一个完整的包接收成功
                    stream_to_mp4->WriteAudioFrameData(a_packet_buffer_offset, a_packet_buffer_data);
                    a_packet_buffer_offset = 0;
                }

            } else {
                std::cerr << "not support PT type " << (int) PT << std::endl;
            }

            socket_offset = socket_offset - (data_offset + data_len );
            memmove(socket_buffer, socket_buffer + data_offset + data_len , socket_offset);
            //std::cout << "BUFFER: " << bytes2HexString(socket_buffer,socket_offset) << endl;


        } else {
            break;
        }
    }

    return true;

}

long RTPBufferReader::BCD2long(const unsigned char *data, int len) {
    long offset = 1;
    long result = 0;
    //17 08 09 21 15 15
    for (int i = 0; i < len; i++) {
        result += offset * (data[len - 1 - i] & 0x0F);
        offset *= 10;
        result += offset * (data[len - 1 - i] >> 4);
        offset *= 10;
    }
    return result;
}

std::string RTPBufferReader::bytes2HexString(unsigned char *data, int len) {
    stringstream ss;
    char temp[3];
    for (int i = 0; i < len; i++) {
        sprintf(temp, "%02x", data[i]);
        ss << temp;
    }
    return ss.str();
}